function reactive(obj) {

    const isObject = (v) => v !== null && typeof v === "object"

    //用户传入已代理过的对象时直接返回映射值
    const toProxy = new WeakMap //obj => observed
    //用户传入值为observed时直接返回observed
    const toRaw = new WeakMap //observed => obj

    //查找缓存
    if(toProxy.has(obj)) {
        return toProxy.get(obj)
    }
    if(toRaw.has(obj)) {
        return obj
    }

    //Proxy外层拦截
    const observed = new Proxy(obj, {
        //target代理目标
        //返回值为获取的值
        get(target, key, receiver) {
            //Reflect是把Object上面的方法移到这里了
            //对比target[key]更加健壮，避免异常
            const res = Reflect.get(target, key, receiver)
            console.log(`get ${target} : ${key}`)

            //收集依赖
            track(target, key)

            return isObject(res) ? reactive(res) : res
        },
        //返回值为是否修改成功
        set(target, key, value, receiver) {
            const res = Reflect.set(target, key, value, receiver)
            console.log(`set ${target} : ${key} : ${value}`)

            //执行回调函数
            trigger(target, key)

            return res
        },
        //返回值为是否修改成功
        deleteProperty(target, key) {
            const res = Reflect.deleteProperty(target, key)
            console.log(`delete ${target} : ${key}`)
            return res
        },
    })

    //缓存
    toProxy.set(obj, observed)
    toRaw.set(observed, obj)

    return observed
}

//保存 响应函数
//执行顺序：effectStack.push(rxEffect) =》 fn() =》 effectStack.pop() =》 return fn()
const effectStack = []
function effect(fn) {
    const rxEffect = function () {
        try {
            effectStack.push(rxEffect)
            //执行函数触发getter => track
            return fn()
        } finally {
            effectStack.pop()
        }
    }
    rxEffect()
    return rxEffect
}

//建立target/key 和 cb之间的映射关系
let targetMap = new WeakMap
function track(target, key) {
    //取出响应函数
    const effect = effectStack[effectStack.length - 1]
    if(effect) {
        //获取依赖表
        let depsMap = targetMap.get(target)
        if(!depsMap) {
            //初始化时不存在需要创建一个新的map对象
            depsMap = new Map
            targetMap.set(target, depsMap)
        }
        //获取key对应的函数集合
        let deps = depsMap.get(key)
        if(!deps) {
            deps = new Set
            depsMap.set(key, deps)
        }
        //将当前effect加入deps中
        if(!deps.has(effect)) {
            deps.add(effect)
        }
    }
}

function trigger(target, key) {
    //获取依赖set
    const depsMap = targetMap.get(target)

    if(depsMap) {
        const deps = depsMap.get(key)
        deps && deps.forEach(effect => effect())
    }
}

const state = reactive({
    counter: 1,
    arr: [1,2,3]
})

// console.log(state)
//
// state.counter ++
// delete state.counter
// state.title = 'hello world'
// state.arr[2] = 4

effect(() => {
    console.log('effect了：', state.counter)
})

state.counter = 2